// index.vue
<template>
  <div id="mMap" class="cesiumMap"></div>
</template>
<script>
import option from "./option";
import { iconMarkerData } from "./testData";
export default {
  props: [],
  components: {},
  data() {
    return {
      viewer: null, // 地图实例
      layerMap: {}, // 所有不同类型的图层集合
      layerClickMap: {}, // 图层点击事件集合
      layerDataSource: null, // 图层数据源集合
    };
  },
  mounted() {
    const token = option.CesiumToken;
    Cesium.Ion.defaultAccessToken = token;
    const tdtKey = option.tdKey;
    const tdtSdKey = "eef5b19f0a9ae1056bef37ee2867027b";

    const tdtImgLayer = new Cesium.WebMapTileServiceImageryProvider({
      url: `http://t0.tianditu.gov.cn/img_w/wmts?tk=${tdtKey}`,
      layer: "img",
      style: "default",
      format: "tiles",
      tileMatrixSetID: "w",
      maximumLevel: 18,
      credit: "天地图影像底图",
    });

    this.viewer = new Cesium.Viewer(mMap, {
      // terrainProvider: Cesium.createWorldTerrain(),
      animation: false, // 是否显示动画控件
      homeButton: false, // 是否显示home键
      geocoder: false, // 是否显示地名查找控件        如果设置为true，则无法查询
      baseLayerPicker: false, // 是否显示图层选择控件
      timeline: false, // 是否显示时间线控件
      fullscreenButton: false, // 是否全屏显示
      scene3DOnly: false, // 如果设置为true，则所有几何图形以3D模式绘制以节约GPU资源
      infoBox: false, // 是否显示点击要素之后显示的信息
      sceneModePicker: false, // 是否显示投影方式控件  三维/二维
      navigationInstructionsInitiallyVisible: false,
      navigationHelpButton: false, // 是否显示帮助信息控件
      selectionIndicator: false, // 是否显示指示器组件
      depthTestAgainstTerrain: true,
    });

    // 添加山东天地图矢量底图
    const tdtSdImgLayer = new Cesium.WebMapTileServiceImageryProvider({
      url: `http://service.sdmap.gov.cn/tileservice/sdrasterpubmap?tk=${tdtSdKey}`,
      layer: "SDRasterPubMap",
      style: "default",
      format: "Mixed",
      tileMatrixSetID: "default028mm",
      tileMatrixLabels: [
        "1",
        "2",
        "3",
        "4",
        "5",
        "6",
        "7",
        "8",
        "9",
        "10",
        "11",
        "12",
        "13",
        "14",
        "15",
        "16",
        "17",
        "18",
      ],
      tilingScheme: new Cesium.GeographicTilingScheme(),
      maximumLevel: 18,
      credit: "天地图影像底图",
    });

    // 添加天地图影像标注图层
    const tdtCvaLayer = new Cesium.WebMapTileServiceImageryProvider({
      url: `http://service.sdmap.gov.cn/tileservice/sdrasterpubmapdj?tk=${tdtSdKey}`,
      layer: "SDPubMap",
      style: "default",
      format: "Mixed",
      tileMatrixSetID: "default028mm",
      tileMatrixLabels: [
        "1",
        "2",
        "3",
        "4",
        "5",
        "6",
        "7",
        "8",
        "9",
        "10",
        "11",
        "12",
        "13",
        "14",
        "15",
        "16",
        "17",
        "18",
      ],
      tilingScheme: new Cesium.GeographicTilingScheme(),
      maximumLevel: 18,
      credit: "山东省天地图注记",
    });

    // 将图层添加到场景中
    this.viewer.imageryLayers.addImageryProvider(tdtImgLayer);
    this.viewer.imageryLayers.addImageryProvider(tdtSdImgLayer);
    this.viewer.imageryLayers.addImageryProvider(tdtCvaLayer);

    // 获取大气效果对象
    var atmosphere = this.viewer.scene.skyAtmosphere;
    // 调整亮度
    atmosphere.brightnessShift = 0.4; // 增加亮度值使天空更明亮

    this.viewer._cesiumWidget._creditContainer.style.display = "none";

    this.viewer.scene.globe.maximumScreenSpaceError = 1.5;
    this.viewer.resolutionScale = 1;

    //设置初始位置
    this.viewer.camera.setView({
      destination: Cesium.Cartesian3.fromDegrees(
        117.80050768028815,
        34.81237996896993,
        15000.26272430837
      ),
      orientation: {
        heading: 0.10445586596464551,
        pitch: -1.0066827593527181,
        roll: 6.283178227240995,
      },
    });

    // 点击事件注册
    const scene = this.viewer.scene;
    const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);

    // 点击事件监听
    handler.setInputAction((e) => {
      var cartesian = this.viewer.camera.pickEllipsoid(
        e.position,
        this.viewer.scene.globe.ellipsoid
      );
      if (cartesian) {
        // 将笛卡尔坐标转换为笛卡尔位置
        var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        // 转换为经纬度
        var longitude = Cesium.Math.toDegrees(cartographic.longitude);
        var latitude = Cesium.Math.toDegrees(cartographic.latitude);

        console.log("经度: " + longitude + ", 纬度: " + latitude);

        // this.markerShowTest("text", { longitude, latitude }); // 文本标注
        // this.markerShowTest("icon", { longitude, latitude }); // 图标标注
      }
      // 获取实体
      const pick = scene.pick(e.position);
      // window.console.log(pick)
      if (pick) {
        this.commonClickHandle(pick);
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    const helper = new Cesium.EventHelper();
    helper.add(this.viewer.scene.globe.tileLoadProgressEvent, (e) => {
      if (e === 0) {
        // me.$emit("mapLoadReady");
        this.mapLoadReady();
      }
    });
  },
  computed: {},
  methods: {
    // 各种标注显示测试
    markerShowTest(type, record) {
      if (type === "text") {
        this.addTxtMarker(
          {
            lng: record.longitude,
            lat: record.latitude,
            cityName: "山东测试",
            total: 100,
          },
          "cityCount"
        );
        return;
      }
      if (type === "icon") {
        this.addLayer(
          iconMarkerData,
          "video",
          require("@/assets/img/video-icon.png"),
          (entity) => {
            console.log(entity, "entity----------------->");
          }
        );
        return;
      }
    },
    // 地图加载完成
    mapLoadReady() {
      this.viewer.scene.globe.depthTestAgainstTerrain = true; // 开启深度测试
      this.markerShowTest("icon", {});
      this.addIconMarker(
        {
          ...iconMarkerData[7],
          lng: "117.83751398302366",
          lat: "34.88653083085197",
        },
        "videoTest"
      );
    },
    // 通用点击事件
    async commonClickHandle(pick) {
      const att = pick.id._att;
      console.log(
        att,
        att.layerCode,
        "点击数据------------------------------>"
      );
    },
    // 添加文字标注
    addTxtMarker(record, layerCode) {
      if (!this.viewer) return;
      // 清空原图层
      if (this.layerMap && this.layerMap[layerCode]) {
        // 移除旧的图标数据源
        this.viewer.dataSources.remove(this.layerMap[layerCode]);
      }
      // 用于图层控制显影,类似图层的概念
      const layerCollection = new Cesium.CustomDataSource(layerCode);
      layerCollection.entities.add({
        name: layerCode,
        att: {
          ...record,
          layerCode,
        },
        position: Cesium.Cartesian3.fromDegrees(record.lng, record.lat),
        label: {
          //文字标签
          text: record.cityName + "\n" + record.total + "座水库",
          font: "500 30px Helvetica", // 15pt monospace
          scale: 0.8,
          style: Cesium.LabelStyle.FILL,
          fillColor: Cesium.Color.WHITE,
          // pixelOffset: new Cesium.Cartesian2((15) + record.label.length * 8.5, -176 / 8),   //偏移量
          showBackground: true,
          backgroundColor: new Cesium.Color(52 / 255, 136 / 255, 255 / 255, 1), //背景顔色
        },
      });
      this.viewer.dataSources.add(layerCollection);
      this.layerMap[layerCode] = layerCollection;
    },
    // 添加图标标注
    addIconMarker(record, layerCode) {
      if (!this.viewer) return;
      // 清空原图层
      if (this.layerMap && this.layerMap[layerCode]) {
        // 移除旧的图标数据源
        this.viewer.dataSources.remove(this.layerMap[layerCode]);
      }
      // 用于图层控制显影,类似图层的概念
      const layerCollection = new Cesium.CustomDataSource(layerCode);
      layerCollection.entities.add({
        name: layerCode,
        att: {
          ...record,
          layerCode,
        },
        position: Cesium.Cartesian3.fromDegrees(record.lng, record.lat),
        billboard: {
          image: record.iconUrl,
          height: 30,
          width: 30,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
          pixelOffset: new Cesium.Cartesian2(0, 6),
        },
        label: {
          text: record.name,
          font: "14px Microsoft YaHei, sans-serif", // 增大字体
          // pixelOffsetScaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 8.0e6, 0.5),
          // scale: 1, // 调整缩放
          fillColor: Cesium.Color.WHITE,
          pixelOffset: new Cesium.Cartesian2(10, 24),
          showBackground: true,
          backgroundPadding: new Cesium.Cartesian2(4, 4), // 增大边距
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
          // disableDepthTestDistance: 1e6, // 调整深度测试距离
          style: {
            fontWeight: "normal", // 调整字体粗细
          },
        },
      });
      this.viewer.dataSources.add(layerCollection);
      this.layerMap[layerCode] = layerCollection;
    },
    /**
     * 添加图层
     * @param records 记录，记录中必须包括lat/lng/name三个属性
     * @param layerCode 图层编码，唯一
     * @param iconUrl 图标
     * @param clickFn 点击事件
     */
    addLayer(records, layerCode, iconUrl, clickFn) {
      if (!this.viewer) return;
      // 清空原图层
      if (this.layerMap[layerCode]) {
        const entities = this.layerDataSource.entities.values; // 获取所有实体
        let entitiesTemp = [...entities];
        for (const element of entitiesTemp) {
          if (layerCode === element.name) {
            this.layerDataSource.entities.remove(element);
          }
        }
        console.log(this.layerDataSource.entities);
      }
      if (clickFn) {
        this.layerClickMap[layerCode] = clickFn;
      }
      // 用于图层控制显影,类似图层的概念
      this.layerMap[layerCode] = [];
      if (!this.layerDataSource) {
        const defaultDataSourceCode = "defaultDataSourceCode";
        this.layerDataSource = new Cesium.CustomDataSource(
          defaultDataSourceCode
        );
        this.layerDataSource.clustering.enabled = true;
        this.layerDataSource.clustering.pixelRange = 20;
        this.layerDataSource.clustering.minimumClusterSize = 2;
        const that = this;
        this.viewer.dataSources.add(this.layerDataSource).then(() => {
          that.addLayerToCluster(
            records,
            layerCode,
            this.layerDataSource,
            iconUrl
          );
        });
        this.layerDataSource.clustering.clusterEvent.addEventListener(
          (clusteredEntities, cluster) => {
            cluster.label.show = false;
            cluster.billboard.show = true;
            // clusteredEntities.forEach(entity => {
            //   entity.label.show = false;
            // });
            // 设置 Clustered Billboard
            cluster.billboard.id = cluster.label.id;
            cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
            // const url =
            //   "../assets/img/big-screen/layer/clusterPop" +
            //   clusteredEntities.length +
            //   ".png";
            const url = require("@/assets/img/layer/clusterPop" +
              clusteredEntities.length +
              ".png");
            cluster.billboard.image = url;
            // const mergedImageUrl = await this.mergeImageAndText(url, clusteredEntities.length);
            // cluster.billboard.image = mergedImageUrl;
            // cluster.billboard.translucencyByDistance = new Cesium.NearFarScalar(100, 5000);
            cluster.billboard.disableDepthTestDistance = 1e6;
          }
        );
      } else {
        this.addLayerToCluster(
          records,
          layerCode,
          this.layerDataSource,
          iconUrl
        );
      }
    },
    addLayerToCluster(records, layerCode, layerDataSource, iconUrl) {
      const { iconSizeWith, iconSizeHeight } = this.getIconSize(records);
      records.forEach(async (record) => {
        let labelName = "";
        switch (layerCode) {
          case "reservoir":
            labelName = record.reservoirName;
            break;
          case "waterStationData":
          case "rainStationData":
          case "syStationData":
          case "wyStationData":
            labelName = record.stationName;
            break;

          case "video":
            labelName = record.deviceName;
            break;
        }
        if (record.lat && record.lng) {
          let iconSrc = iconUrl;
          // 添加 点位到地图上
          if (layerCode === "video" && record.liveStatus === 0) {
            iconSrc = require("@/assets/img/video-icon-gray.png");
          }
          layerDataSource.entities.add({
            name: layerCode,
            att: {
              ...record,
              layerCode,
            },
            position: Cesium.Cartesian3.fromDegrees(
              parseFloat(record.lng),
              parseFloat(record.lat)
            ),
            label: {
              text: labelName,
              show: true,
              font: "14px Microsoft YaHei, sans-serif", // 增大字体
              // pixelOffsetScaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 8.0e6, 0.5),
              // scale: 1, // 调整缩放
              fillColor: Cesium.Color.WHITE,
              pixelOffset: new Cesium.Cartesian2(0, 24),
              showBackground: true,
              backgroundPadding: new Cesium.Cartesian2(4, 4), // 增大边距
              heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
              // disableDepthTestDistance: 1e6, // 调整深度测试距离
              style: {
                fontWeight: "normal", // 调整字体粗细
              },
            },
            billboard: {
              // 图标
              image: record.iconUrl || iconSrc,
              width: iconSizeWith,
              height: iconSizeHeight,
              pixelOffset: new Cesium.Cartesian2(0, -6), // 偏移量
              heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
              disableDepthTestDistance: 1e6, // 调整深度测试距离
            },
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
          });
          if (record.imageArr) {
            record.imageArr.forEach((item, index) => {
              const tempEntity = layerDataSource.entities.add({
                name: layerCode,
                position: Cesium.Cartesian3.fromDegrees(
                  +record.lng,
                  +record.lat
                ),
                billboard: {
                  // 图标
                  image: item.iconUrl,
                  width: 14,
                  height: 14,
                  pixelOffset: new Cesium.Cartesian2(18, index * 18 - 90), // 偏移量
                  renderOrder: 0,
                },
              });
            });
          }
        }
      });
    },
    getIconSize(records) {
      if (Array.isArray(records) && records.length > 0) {
        const child = records[0];
        if (child.iconSizeWith && child.iconSizeHeight) {
          return {
            iconSizeWith: child.iconSizeWith,
            iconSizeHeight: child.iconSizeHeight,
          };
        }
      }
      return { iconSizeWith: 30, iconSizeHeight: 30 };
    },
  },
};
</script>
<style scoped>
.cesiumMap {
  width: 100%;
  height: 100vh;
}
</style>
